package com.maiji.cloud.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.google.common.collect.Lists;
import com.maiji.cloud.entities.login.AreaInfo;
import com.maiji.cloud.entities.shopingmall.ProvinceCity;
import com.maiji.cloud.entities.shopingmall.RuleFreight;
import com.maiji.cloud.mapper.RuleFreightMapper;
import com.maiji.cloud.request.ReqMetaData;
import com.maiji.cloud.response.*;
import com.maiji.cloud.response.shopingmall.DeliveryResData;
import com.maiji.cloud.response.shopingmall.ShopingOrderResData;
import com.maiji.cloud.service.ProvinceCityService;
import com.maiji.cloud.service.RuleFreightService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.maiji.cloud.utils.Arith;
import com.maiji.cloud.utils.RedisUtil;
import com.maiji.cloud.utils.UUID_MD5;
import org.eclipse.jetty.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Transactional
public class RuleFreightServiceImpl extends ServiceImpl<RuleFreightMapper, RuleFreight> implements RuleFreightService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ProvinceCityService provinceCityService;

    @Override
    public BaseMetaResDto<List<RuleFreight>> findAllRuleFreights(RuleFreight ruleFreight, ReqMetaData metaData) {
        EntityWrapper<RuleFreight> entityWrapper = new EntityWrapper<>();
        String uuId = ruleFreight.getUuId();
        if (StringUtil.isNotBlank(uuId)) entityWrapper.eq("uu_id", uuId);
        String delivery = ruleFreight.getDelivery();
        if (StringUtil.isNotBlank(delivery)) entityWrapper.eq("delivery", delivery);
        String areaNames = ruleFreight.getAreaNames();
        if (StringUtil.isNotBlank(areaNames)) entityWrapper.like("area_names", areaNames);
        entityWrapper.orderAsc(Arrays.asList("delivery", "head_weight", "freight", "moreFreight"));
        Page<RuleFreight> page = selectPage(new Page<>(metaData.getPage(), metaData.getSize()), entityWrapper);
        ResMetaData resMetaData = new ResMetaData(page.getCurrent(), page.getSize(), page.getTotal());
        return new BaseMetaResDto<List<RuleFreight>>(Status.SUCCESS).setData(page.getRecords()).setResMetaData(resMetaData);
    }

    @Override
    public BaseResDto add_updRuleFreight(RuleFreight ruleFreight) {
        if (StringUtil.isBlank(ruleFreight.getUuId()))
            if (! insert(ruleFreight.setUuId(UUID_MD5.getUUID())))
                return new BaseResDto(Status.ERROR);
        if (StringUtil.isNotBlank(ruleFreight.getUuId()))
            if (! updateById(ruleFreight)) return new BaseResDto(Status.ERROR);
        return new BaseResDto(Status.SUCCESS);
    }

    @Override
    public BaseDataResDto<List<ProvinceCity>> findAllProvinceCity () {
        List<ProvinceCity> provinces = provinceCityService.selectList(new EntityWrapper<ProvinceCity>().eq("pid", 0));
        Map<Integer, List<ProvinceCity>> citiesMap = provinceCityService.selectList(new EntityWrapper<ProvinceCity>().ne("pid", 0))
                .parallelStream().collect(Collectors.groupingBy(ProvinceCity::getPid));
        List<ProvinceCity> provinceCities = provinces.parallelStream().map(province -> {
            List<ProvinceCity> cities = citiesMap.get(province.getUuId());
            return province.setChildrenList(cities);
        }).collect(Collectors.toList());
        return new BaseDataResDto<List<ProvinceCity>>(Status.SUCCESS).setData(provinceCities);
    }

    @Override
    public RuleFreight findAllRuleFreightsByOrder(ShopingOrderResData shopingOrderResData, AreaInfo areaInfo, String rfId) {
        String province = areaInfo.getProvince();
        String city = areaInfo.getCity();
        String redisKey = RedisUtil.getRedisKey(REDISNAMESPACE, province + "/" + city);
        List<RuleFreight> ruleFreights = RedisUtil.getList(stringRedisTemplate, redisKey, 0, 9, RuleFreight.class);
        if (ruleFreights.size() == 0) {
            Wrapper<RuleFreight> cityWrapper = new EntityWrapper<RuleFreight>()
                    .eq("userable", true)
                    .like("area_names", "@" + province ).or()
                    .like("area_names", "#" + province)
                    .like("area_names", "/" + city);
            ruleFreights = selectList(cityWrapper);
        }
        if (ruleFreights.size() > 0) {  // 选择默认或用户选择的快递计算规则
            List<DeliveryResData> deliveryResDataList = ruleFreights.parallelStream().map(rf -> {
                Double freight = 0.00;  //  计算快递费
                Double freeFreight = rf.getFreeFreight();
                Integer headWeight = rf.getHeadWeight();
                if (shopingOrderResData.getScAmount() < freeFreight)   // 购物金额 < 包邮购物金额
                    if (shopingOrderResData.getWeightTotal() > headWeight) {  // 物流总重量 > 物流首重量
                        Integer moreWeight = shopingOrderResData.getWeightTotal() - headWeight;
                        Integer more = moreWeight / 1000 + 1;
                        freight = Arith.add(2, rf.getFreight(), Arith.multiplys(2, rf.getMoreFreight(), more));
                    } else freight = rf.getFreight();
                return new DeliveryResData().setUuId(rf.getUuId()).setDelivery(rf.getDelivery()).setDeliveryFee(freight);
            }).collect(Collectors.toList());
            shopingOrderResData.setDeliveryList(deliveryResDataList);
            RedisUtil.setList(stringRedisTemplate, redisKey, ruleFreights);
            Optional<RuleFreight> optional = Optional.empty();
            if (StringUtil.isNotBlank(rfId)) optional = ruleFreights.parallelStream().filter(rf -> rf.getUuId().equals(rfId)).findFirst();
            if (optional.isPresent()) return optional.get();
            else optional = ruleFreights.parallelStream().filter(rf -> rf.getDelivery().equals("申通快递")).findFirst();
            if (optional.isPresent()) return optional.get();
        }
        return null;
    }

}
